package show.me.the.money.servlet;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import show.me.the.money.accredit.User;
import show.me.the.money.config.reportSchema.ReportSchemaController;
import show.me.the.money.config.reportSchema.define.ReportSchema;
import show.me.the.money.dictionary.Dictionaries;
import show.me.the.money.dictionary.Dictionary;
import show.me.the.money.util.context.Context;
import show.me.the.money.util.context.HashMapContext;
import show.me.the.money.util.context.UserContext;
import freemarker.template.Configuration;
import freemarker.template.Template;
@SuppressWarnings({"unchecked"})
public class ChartDataLoader extends HttpServlet implements Servlet {;

	private static final long serialVersionUID = 5823714493803495747L;
	private static Log logger = LogFactory.getLog(ChartDataLoader.class);
	private static Pattern pattern = Pattern.compile("([^/]+)\\.chart");
	private static WebApplicationContext wac;
	
	
	public void init(ServletConfig oCfg) throws ServletException {
		wac = WebApplicationContextUtils.getRequiredWebApplicationContext(oCfg.getServletContext());
		logger.info("Servlet init");
	}
	
	private String getChartId(String url){
		Matcher matcher = pattern.matcher(url);
		if(matcher.find()){
	        return matcher.group(1);
		}
		return null;
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response){
		HashMap<String,Object> query = parseQueryString(request.getQueryString());
		doChartService(request,response,query);
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response){
		HashMap<String,Object> query = Dispatcher.parseRequest(request);
		doChartService(request,response,query);	
	}
	
	private void doChartService(HttpServletRequest request, HttpServletResponse response,HashMap<String,Object> query){
		String id = getChartId(request.getRequestURI());
		if(StringUtils.isEmpty(id)){
			logger.error("Request Url's arg [chartId id] missing");
			return;
		}
		//init context
		Context ctx = initContext(request);
		Context qCtx = new HashMapContext(query);
		ctx.putCtx("q", qCtx);
		ctx.put(Context.APP_CONTEXT, wac);
		
		String path=(String)query.get("path");
		if(path!=null && !path.equals("undefined")){
			path=path.replace("_", "/");
			id=path+"/"+id;
		}
		ReportSchema reportSchema = ReportSchemaController.instance().getSchemaDynamic(id,ctx);
		//for result
		List<HashMap> rs = reportSchema.run(ctx);
		if(rs.size() > 0){
			try {				
				FreeMarkerConfigurer fc = (FreeMarkerConfigurer)wac.getBean("freeMarkerConfigurer");
				Configuration freemarker = fc.getConfiguration();
				String chartTemplate = (String)query.get("template");  //added by zhouz
				if(chartTemplate==null || chartTemplate.equals("undefined")){
					chartTemplate=reportSchema.getChartTemplate();
				}
				Template t = freemarker.getTemplate(chartTemplate+".ftl");
				Writer writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream())); 
				response.addHeader("content-type","text/xml;charset=gb2312");
				HashMap<String,Object> data = perpareData(reportSchema,rs,query);
				data.put("chartId", query.get("chartId"));
				data.put("subTitle", reportSchema.getSubTitle(ctx));
				data.put("limit", ctx.get("totalCount"));
				String title=(String)query.get("title");
				if(title!=null && !title.equals("undefined")){
					data.put("title", URLDecoder.decode(title, "utf-8")+reportSchema.getTitle());
				}
				t.process(data, writer);
			} 
			catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
		else{
			try {
				Writer writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream())); 
				response.addHeader("content-type","text/xml;charset=gb2312");
				writer.write("<chart/>");
				writer.close();
				//response.getWriter().write("<chart/>");
			} 
			catch (IOException e) {
			}
			
		}
	}
	
	private HashMap<String,Object> perpareData(ReportSchema reportSchema,List<HashMap> rs,HashMap query){
		HashMap<String,Object> data = new HashMap<String,Object>();
		List<HashMap<String,Object>> headers=reportSchema.getHeaders();
		if(query.get("navDic")!=null && query.get("columns")!=null){
			Dictionary dic= Dictionaries.instance().getDic((String)query.get("navDic"));
			List<Object> cols=null;
			try {
				ObjectMapper mapper = new ObjectMapper();
				cols = mapper.readValue((String)query.get("columns"), List.class);
			} 
			catch (Exception e) {
				logger.error("parse reportCondition failed:", e);
			}
			
			for(int i=0;i<cols.size();i++){
				HashMap<String,Object> h=(HashMap<String,Object>)headers.get(headers.size()-1).clone();
				String c=(String)cols.get(i);
				int renderIndex= Integer.parseInt(String.valueOf(h.get("renderIndex")))+i+1;
				h.put("id", c);
				h.put("alias", dic.getItem((String)cols.get(i)).getText());
				h.put("renderIndex",String.valueOf(renderIndex));
				h.remove("hidden");
				headers.add(h);
			}
		}
		data.put("title", reportSchema.getTitle());
		data.put("headers",headers );
		int limit = reportSchema.getChartLimit();
		if(limit == 0){
			limit = rs.size();
		}
		HashMap diggers = reportSchema.getDiggers();
		if(diggers != null){
			data.put("diggers", diggers);
		}
		data.put("rs", rs);
		data.put("limit",limit);
		return data;
	}
	
	public static HashMap<String,Object> parseQueryString(String q){
		HashMap<String,Object> query = new  HashMap<String,Object>();
		query.put("chartId", "");
		q = q.substring(2);
		if(q != null){
			int p = q.indexOf("@");
			if(p > -1){
				String[] qus = q.split("@");
				int size = qus.length;
					for(int i = 0; i < size; i ++){
						String[] kv = qus[i].split(";");
						if(kv.length == 2){
							try {
								String key = URLDecoder.decode(kv[0],"utf-8");
								String value = URLDecoder.decode(kv[1],"utf-8").replace("%5B", "[").
								replace("%5D", "]").
								replace("%2B","+");
								query.put(key,value);
							} 
							catch (UnsupportedEncodingException e) {
								logger.error("parseQueryStringFailed:", e);
							}
						}
					}
			}
			else{
				String[] kv = q.split(";");
				if(kv.length == 2){
					try {
						String key = URLDecoder.decode(kv[0],"utf-8");
						String value = URLDecoder.decode(kv[1],"utf-8").replace("%5B", "[").
						replace("%5D", "]").
						replace("%2B","+");
						query.put(key,value);
					} 
					catch (UnsupportedEncodingException e) {
						logger.error("parseQueryStringFailed:", e);
					}
				}
			}
		}
		return query;
	}
	
	
	public static Context initContext(HttpServletRequest request){
		Context ctx = Dispatcher.createContext(request);
		User user = Dispatcher.getUser(request);
		if(user != null){
			Context userCtx = new UserContext(user);
			ctx.putCtx("user", userCtx);
		}
		return ctx;
	}
	
}